<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Filtering revisited</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../index.html" title="Chapter 1. Boost.Log v2">
<link rel="up" href="../tutorial.html" title="Tutorial">
<link rel="prev" href="formatters.html" title="Log record formatting">
<link rel="next" href="wide_char.html" title="Wide character logging">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr><td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td></tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="formatters.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../tutorial.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="wide_char.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="log.tutorial.advanced_filtering"></a><a class="link" href="advanced_filtering.html" title="Filtering revisited">Filtering revisited</a>
</h3></div></div></div>
<p>
        We've already touched filtering in the previous sections but we barely scratched
        the surface. Now that we are able to add attributes to log records and set
        up sinks, we can build however complex filtering we need. Let's consider
        this example:
      </p>
<p>
</p>
<pre class="programlisting"><span class="identifier">BOOST_LOG_ATTRIBUTE_KEYWORD</span><span class="special">(</span><span class="identifier">line_id</span><span class="special">,</span> <span class="string">"LineID"</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span><span class="special">)</span>
<span class="identifier">BOOST_LOG_ATTRIBUTE_KEYWORD</span><span class="special">(</span><span class="identifier">severity</span><span class="special">,</span> <span class="string">"Severity"</span><span class="special">,</span> <span class="identifier">severity_level</span><span class="special">)</span>
<span class="identifier">BOOST_LOG_ATTRIBUTE_KEYWORD</span><span class="special">(</span><span class="identifier">tag_attr</span><span class="special">,</span> <span class="string">"Tag"</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">)</span>

<span class="keyword">void</span> <span class="identifier">init</span><span class="special">()</span>
<span class="special">{</span>
    <span class="comment">// Setup the common formatter for all sinks</span>
    <span class="identifier">logging</span><span class="special">::</span><span class="identifier">formatter</span> <span class="identifier">fmt</span> <span class="special">=</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">stream</span>
        <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">setw</span><span class="special">(</span><span class="number">6</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">setfill</span><span class="special">(</span><span class="char">'0'</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="identifier">line_id</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">setfill</span><span class="special">(</span><span class="char">' '</span><span class="special">)</span>
        <span class="special">&lt;&lt;</span> <span class="string">": &lt;"</span> <span class="special">&lt;&lt;</span> <span class="identifier">severity</span> <span class="special">&lt;&lt;</span> <span class="string">"&gt;\t"</span>
        <span class="special">&lt;&lt;</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">if_</span><span class="special">(</span><span class="identifier">expr</span><span class="special">::</span><span class="identifier">has_attr</span><span class="special">(</span><span class="identifier">tag_attr</span><span class="special">))</span>
           <span class="special">[</span>
               <span class="identifier">expr</span><span class="special">::</span><span class="identifier">stream</span> <span class="special">&lt;&lt;</span> <span class="string">"["</span> <span class="special">&lt;&lt;</span> <span class="identifier">tag_attr</span> <span class="special">&lt;&lt;</span> <span class="string">"] "</span>
           <span class="special">]</span>
        <span class="special">&lt;&lt;</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">smessage</span><span class="special">;</span>

    <span class="comment">// Initialize sinks</span>
    <span class="keyword">typedef</span> <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">synchronous_sink</span><span class="special">&lt;</span> <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">text_ostream_backend</span> <span class="special">&gt;</span> <span class="identifier">text_sink</span><span class="special">;</span>
    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special">&lt;</span> <span class="identifier">text_sink</span> <span class="special">&gt;</span> <span class="identifier">sink</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special">&lt;</span> <span class="identifier">text_sink</span> <span class="special">&gt;();</span>

    <span class="identifier">sink</span><span class="special">-&gt;</span><span class="identifier">locked_backend</span><span class="special">()-&gt;</span><span class="identifier">add_stream</span><span class="special">(</span>
        <span class="identifier">boost</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special">&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ofstream</span> <span class="special">&gt;(</span><span class="string">"full.log"</span><span class="special">));</span>

    <span class="identifier">sink</span><span class="special">-&gt;</span><span class="identifier">set_formatter</span><span class="special">(</span><span class="identifier">fmt</span><span class="special">);</span>

    <span class="identifier">logging</span><span class="special">::</span><span class="identifier">core</span><span class="special">::</span><span class="identifier">get</span><span class="special">()-&gt;</span><span class="identifier">add_sink</span><span class="special">(</span><span class="identifier">sink</span><span class="special">);</span>

    <span class="identifier">sink</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special">&lt;</span> <span class="identifier">text_sink</span> <span class="special">&gt;();</span>

    <span class="identifier">sink</span><span class="special">-&gt;</span><span class="identifier">locked_backend</span><span class="special">()-&gt;</span><span class="identifier">add_stream</span><span class="special">(</span>
        <span class="identifier">boost</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special">&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ofstream</span> <span class="special">&gt;(</span><span class="string">"important.log"</span><span class="special">));</span>

    <span class="identifier">sink</span><span class="special">-&gt;</span><span class="identifier">set_formatter</span><span class="special">(</span><span class="identifier">fmt</span><span class="special">);</span>

    <span class="identifier">sink</span><span class="special">-&gt;</span><span class="identifier">set_filter</span><span class="special">(</span><span class="identifier">severity</span> <span class="special">&gt;=</span> <span class="identifier">warning</span> <span class="special">||</span> <span class="special">(</span><span class="identifier">expr</span><span class="special">::</span><span class="identifier">has_attr</span><span class="special">(</span><span class="identifier">tag_attr</span><span class="special">)</span> <span class="special">&amp;&amp;</span> <span class="identifier">tag_attr</span> <span class="special">==</span> <span class="string">"IMPORTANT_MESSAGE"</span><span class="special">));</span>

    <span class="identifier">logging</span><span class="special">::</span><span class="identifier">core</span><span class="special">::</span><span class="identifier">get</span><span class="special">()-&gt;</span><span class="identifier">add_sink</span><span class="special">(</span><span class="identifier">sink</span><span class="special">);</span>

    <span class="comment">// Add attributes</span>
    <span class="identifier">logging</span><span class="special">::</span><span class="identifier">add_common_attributes</span><span class="special">();</span>
<span class="special">}</span>
</pre>
<p>
      </p>
<p>
        <a href="../../../../../../libs/log/example/doc/tutorial_filtering.cpp" target="_top">See the complete
        code</a>.
      </p>
<p>
        In this sample we initialize two sinks - one for the complete log file and
        the other for important messages only. Both sinks will be writing to text
        files with the same log record format, which we initialize first and save
        to the <code class="computeroutput"><span class="identifier">fmt</span></code> variable. The
        <code class="computeroutput"><a class="link" href="../../boost/log/basic_formatter.html" title="Class template basic_formatter">formatter</a></code> type is
        a type-erased function object with the formatter calling signature; in many
        respects it can be viewed similar to <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">function</span></code>
        or <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">function</span></code> except that it is never empty.
        There is also <code class="computeroutput"><a class="link" href="../../boost/log/filter.html" title="Class filter">a similar function object</a></code>
        for filters.
      </p>
<p>
        Notably, the formatter itself contains a filter here. As you can see, the
        format contains a conditional part that is only present when log records
        contain the "Tag" attribute. The <a class="link" href="../detailed/expressions.html#log.detailed.expressions.predicates.has_attr" title="Attribute presence filter"><code class="computeroutput"><span class="identifier">has_attr</span></code></a> predicate checks whether
        the record contains the "Tag" attribute value and controls whether
        it is put into the file or not. We used the attribute keyword to specify
        the name and type of the attribute for the predicate, but it is also possible
        to specify them in the <a class="link" href="../detailed/expressions.html#log.detailed.expressions.predicates.has_attr" title="Attribute presence filter"><code class="computeroutput"><span class="identifier">has_attr</span></code></a> call site. Conditional
        formatters are explained in more details <a class="link" href="../detailed/expressions.html#log.detailed.expressions.formatters.conditional" title="Conditional formatters">here</a>.
      </p>
<p>
        Further goes the initialization of the two sinks. The first sink does not
        have any filter, which means it will save every log record to the file. We
        call <code class="computeroutput"><span class="identifier">set_filter</span></code> on the second
        sink to only save log records with severity no less than <code class="computeroutput"><span class="identifier">warning</span></code>
        or having a "Tag" attribute with value "IMPORTANT_MESSAGE".
        As you can see, the filter syntax resembles usual C++ very much, especially
        when attribute keywords are used.
      </p>
<p>
        Like with formatters, it is also possible to use custom functions as filters.
        Fundamentally, a filter function must support the following signature:
      </p>
<pre class="programlisting"><span class="keyword">bool</span> <span class="special">(</span><span class="identifier">logging</span><span class="special">::</span><span class="identifier">attribute_value_set</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">attrs</span><span class="special">);</span>
</pre>
<p>
        When the filter is called, <code class="computeroutput"><span class="identifier">attrs</span></code>
        will contain a complete set of attribute values, which can be used to decide
        whether the log record should be passed or suppressed. If the filter returns
        <code class="computeroutput"><span class="keyword">true</span></code>, the log record will be
        constructed and further processed by sinks. Otherwise, the record will be
        discarded.
      </p>
<p>
        <a href="https://www.boost.org/doc/libs/release/libs/phoenix/doc/html/index.html" target="_top">Boost.Phoenix</a>
        can be very helpful in constructing filters. It allows to automate extraction
        of attribute values from the <code class="computeroutput"><span class="identifier">attrs</span></code>
        set as its <code class="computeroutput"><span class="identifier">bind</span></code> implementation
        is compatible with attribute placeholders. The previous example can be modified
        in the following way:
      </p>
<p>
</p>
<pre class="programlisting"><span class="keyword">bool</span> <span class="identifier">my_filter</span><span class="special">(</span><span class="identifier">logging</span><span class="special">::</span><span class="identifier">value_ref</span><span class="special">&lt;</span> <span class="identifier">severity_level</span><span class="special">,</span> <span class="identifier">tag</span><span class="special">::</span><span class="identifier">severity</span> <span class="special">&gt;</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">level</span><span class="special">,</span>
               <span class="identifier">logging</span><span class="special">::</span><span class="identifier">value_ref</span><span class="special">&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">,</span> <span class="identifier">tag</span><span class="special">::</span><span class="identifier">tag_attr</span> <span class="special">&gt;</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">tag</span><span class="special">)</span>
<span class="special">{</span>
    <span class="keyword">return</span> <span class="identifier">level</span> <span class="special">&gt;=</span> <span class="identifier">warning</span> <span class="special">||</span> <span class="identifier">tag</span> <span class="special">==</span> <span class="string">"IMPORTANT_MESSAGE"</span><span class="special">;</span>
<span class="special">}</span>

<span class="keyword">void</span> <span class="identifier">init</span><span class="special">()</span>
<span class="special">{</span>
    <span class="comment">// ...</span>

    <span class="keyword">namespace</span> <span class="identifier">phoenix</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">phoenix</span><span class="special">;</span>
    <span class="identifier">sink</span><span class="special">-&gt;</span><span class="identifier">set_filter</span><span class="special">(</span><span class="identifier">phoenix</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(&amp;</span><span class="identifier">my_filter</span><span class="special">,</span> <span class="identifier">severity</span><span class="special">.</span><span class="identifier">or_none</span><span class="special">(),</span> <span class="identifier">tag_attr</span><span class="special">.</span><span class="identifier">or_none</span><span class="special">()));</span>

    <span class="comment">// ...</span>
<span class="special">}</span>
</pre>
<p>
      </p>
<p>
        As you can see, the custom filter receives attribute values as separate arguments,
        wrapped into the <a class="link" href="../detailed/utilities.html#log.detailed.utilities.value_ref" title="Value reference wrapper"><code class="computeroutput"><span class="identifier">value_ref</span></code></a> template. This wrapper
        contains an optional reference to the attribute value of the specified type;
        the reference is valid if the log record contains the attribute value of
        the required type. The relational operators used in <code class="computeroutput"><span class="identifier">my_filter</span></code>
        can be applied unconditionally because they will automatically return <code class="computeroutput"><span class="keyword">false</span></code> if the reference is not valid. The rest
        is done with the <code class="computeroutput"><span class="identifier">bind</span></code> expression
        which will recognize the <code class="computeroutput"><span class="identifier">severity</span></code>
        and <code class="computeroutput"><span class="identifier">tag_attr</span></code> keywords and
        extract the corresponding values before passing them to <code class="computeroutput"><span class="identifier">my_filter</span></code>.
      </p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../doc/src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
          Because of limitations related to the integration with <a href="https://www.boost.org/doc/libs/release/libs/phoenix/doc/html/index.html" target="_top">Boost.Phoenix</a>
          (see <a href="https://svn.boost.org/trac/boost/ticket/7996" target="_top">#7996</a>), it is required to explicitly specify the fallback policy
          in case if the attribute value is missing, when attribute keywords are
          used with <code class="computeroutput"><span class="identifier">phoenix</span><span class="special">::</span><span class="identifier">bind</span></code> or <code class="computeroutput"><span class="identifier">phoenix</span><span class="special">::</span><span class="identifier">function</span></code>.
          In the example above, this is done by calling <code class="computeroutput"><span class="identifier">or_none</span></code>,
          which results in an empty <a class="link" href="../detailed/utilities.html#log.detailed.utilities.value_ref" title="Value reference wrapper"><code class="computeroutput"><span class="identifier">value_ref</span></code></a> if the value is not
          found. In other contexts this policy is the default. There are <a class="link" href="../detailed/expressions.html#log.detailed.expressions.attr.fallback_policies" title="Customizing fallback policy">other
          policies</a> that can be used instead.
        </p></td></tr>
</table></div>
<p>
        You can try how this works by compiling and running the <a href="../../../../../../libs/log/example/doc/tutorial_filtering.cpp" target="_top">test</a>.
      </p>
</div>
<div class="copyright-footer">Copyright © 2007-2024 Andrey Semashev<p>
        Distributed under the Boost Software License, Version 1.0. (See accompanying
        file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>).
      </p>
</div>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="formatters.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../tutorial.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="wide_char.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>
